package com.lcredu.lcrliving.commodity.service.impl;

import com.lcredu.common.util.PageUtils;
import com.lcredu.common.util.Query;
import com.lcredu.lcrliving.commodity.vo.Catalog2Vo;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.lcredu.lcrliving.commodity.dao.CategoryDao;
import com.lcredu.lcrliving.commodity.entity.CategoryEntity;
import com.lcredu.lcrliving.commodity.service.CategoryService;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    //核心方法
    //这里我们会使用到流式计算(stream api)+递归=>解决方案
    @Override
    public List<CategoryEntity> listTree() {
        //1.查出所有的分类数据
        List<CategoryEntity> entities = baseMapper.selectList(null);

        //2. 组装成层级树形结构[stream api + 递归]
        //思路

        List<CategoryEntity> categoryTree = entities.stream().filter(categoryEntity -> {
            //2.1 对entities进行过滤,返回一级分类
            return categoryEntity.getParentId() == 0;
        }).map(category -> {
            //2.2 进行map映射操作，给每个一级分类设置对应的子分类(这个过程会使用到递归)
            category.setChildrenCategories(getChildrenCategories(category, entities));
            return category;
        }).sorted((category1, category2) -> {
            //2.3 进行排序sorted操作,按照升序排列
            return (category1.getSort() == null ? 0 : category1.getSort()) -
                    (category2.getSort() == null ? 0 : category2.getSort());
        }).collect(Collectors.toList());//2.4 将处理好的数据进行一个收集collect到集合中

        //3.返回带层级关系的数据-树形


        return categoryTree;

    }

    /**
     * 递归查询所有分类的子分类
     *
     * @param root :一级分类的数据
     * @param all  :所有数据的集合(即上个方法的entities)
     *             该方法的任务就是把root下所有子分类的层级关系组织好(有多少级就处理多少级)，并返回
     */
    private List<CategoryEntity> getChildrenCategories(CategoryEntity root, List<CategoryEntity> all) {
        //过滤
        List<CategoryEntity> children =
                all.stream().filter(categoryEntity -> {//这里在处理all里面的每个个体categoryEntity
                    //categoryEntity.getParentId() == root.getId()
                    //返回的是Long 包装类型 == 表示是对对象的比较
//            return categoryEntity.getParentId() == root.getId();//返回一级分类下的子分类(父id=root的Id)
                    //解决方法1
                    //return categoryEntity.getParentId().longValue() == root.getId().longValue();//返回一级分类下的子分类(父id=root的Id)
                    //解决方法2 用equals进行对数值的比较
                    return categoryEntity.getParentId().equals(root.getId());//返回一级分类下的子分类(父id=root的Id)
                }).map(categoryEntity -> {
                    //1. 找到子分类,并设置递归
                    categoryEntity.setChildrenCategories(getChildrenCategories(categoryEntity, all));
                    return categoryEntity;
                }).sorted((category1, category2) -> {
                    //按照sort排序--升序
                    return (category1.getSort() == null ? 0 : category1.getSort()) -
                            (category2.getSort() == null ? 0 : category2.getSort());
                }).collect(Collectors.toList());

        return children;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 返回的对象是cascadedCategoryId,数据形式是[1,21,301]
     * 递归
     *
     * @param categoryId
     * @return
     */
    @Override
    public Long[] getCascadedCategoryId(Long categoryId) {
        //1.创建一个集合,把层级关系收集到集合中
        List<Long> cascadedCategoryId = new ArrayList<>();

        //2.调用方法进行处理--递归
        //getParentCategoryId是引用传递,所以直接影响到这个方法的cascadedCategoryId集合
        //返回的数据如[301,21,1]
        getParentCategoryId(categoryId, cascadedCategoryId);

        //3. 将cascadedCategoryId反转
        Collections.reverse(cascadedCategoryId);
        return cascadedCategoryId.toArray(new Long[cascadedCategoryId.size()]);
    }


    /**
     * 编写方法,根据categoryId递归查找层级关系
     * 比如接收到categoryId 301 -> parentId->...
     * <p>
     * cascadedCategoryId => [301]
     */

    private List<Long> getParentCategoryId(Long categoryId, List<Long> cascadedCategoryId) {
        //1.先把categoryId放入到
        cascadedCategoryId.add(categoryId);
        //2.根据categoryId得到他的categoryEntity
        CategoryEntity categoryEntity = this.getById(categoryId);
        //3.判断categoryEntity的parentId是否为0,如果不为0,说明他还有上级分类
        //就递归处理
        //getParentId返回类型是0L所以equals判断为false导致系统异常错误发生
        if (!categoryEntity.getParentId().equals(0L)) {
            //[301,21,1]
            getParentCategoryId(categoryEntity.getParentId(), cascadedCategoryId);
        }
        return cascadedCategoryId;
    }

    //返回一级分类
    @Override
    public List<CategoryEntity> getLevel1Categories() {
        QueryWrapper<CategoryEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", 0);
        List<CategoryEntity> categoryEntities = this.baseMapper.selectList(queryWrapper);
        return categoryEntities;
    }

    /**
     * @param selectList 所有的分类信息
     * @param parentCId  根据parentId返回对应的数据
     * @return
     */
    private List<CategoryEntity> getParent_cid(List<CategoryEntity> selectList,
                                               Long parentCId) {
        //流式计算fileter
        List<CategoryEntity> categoryEntities = selectList.stream().filter(item -> {
            return item.getParentId().equals(parentCId);
        }).collect(Collectors.toList());

        return categoryEntities;
    }


    /**
     * @return 二级分类, 三级分类
     * 按照规定格式
     * 流式计算--map
     * *&……￥%￥%……&**……
     * 增加辅助方法,通过parentId获取对应的下级
     */
    @Override
    public Map<String, List<Catalog2Vo>> getCataLogJson() {
        //先得到所有数据->程序中进行业务处理->Map<String,List<Catalog2Vo>>
        List<CategoryEntity> selectList = this.baseMapper.selectList(null);

//        System.out.println("selectList--->" + selectList);

        //从一级分类->二级分类->三级分类

        //得到所有的一级分类
        List<CategoryEntity> level1Categories = getParent_cid(selectList, 0L);

        //遍历一级分类->Map(String,List<Catalog2Vo>)
        Map<String, List<Catalog2Vo>> categoryMap =
                level1Categories.stream().collect(
                        Collectors.toMap(k -> {
                            return k.getId().toString();
                        }, v -> {
                            //业务处理List<Catalog2Vo>
                            List<Catalog2Vo> catalog2Vos = new ArrayList<>();
                            //得到1级分类对应的2级分类
                            List<CategoryEntity> level2Categories = getParent_cid(selectList, v.getId());

                            //遍历二级分类
                            if (level2Categories != null && level2Categories.size() > 0)
                                catalog2Vos = level2Categories.stream().map(l2 -> {
                                    Catalog2Vo catalog2Vo = new Catalog2Vo(v.getId().toString(), null, l2.getId().toString(), l2.getName());

                                    //遍历l2对应的三级分类
                                    List<CategoryEntity> level3Categories = getParent_cid(selectList, l2.getId());
                                    if (level3Categories != null && level3Categories.size() > 0) {
                                        List<Catalog2Vo.Category3Vo> category3Vos = level3Categories.stream().map(l3 -> {
                                            //构建当前二级分类对应的三级分类对象Catalog2Vo.Category3Vo category3Vo =
                                            Catalog2Vo.Category3Vo category3Vo = new Catalog2Vo.Category3Vo(l2.getId().toString(), l3.getId().toString(), l3.getName());
                                            return category3Vo;
                                        }).collect(Collectors.toList());
                                        catalog2Vo.setCatalog3List(category3Vos);
                                    }
                                    return catalog2Vo;
                                }).collect(Collectors.toList());


                            return catalog2Vos;
                        }));
        return categoryMap;
    }
}
